import pdfplumber
import fitz
import os


def detect_label_bboxes(pdf_path):
    """ 检测所有标签的边界框坐标 """
    bboxes = []  # 用于存储每个标签的边界框
    with pdfplumber.open(pdf_path) as pdf:
        for page in pdf.pages:
            # 提取页面上的所有矩形
            rects = page.rects
            texts = page.extract_words()

            # 如果找到了矩形，处理普通矩形
            if rects and texts[0]['text'] != 'ETIQUETA':
                print("第一种")
                for rect in rects:
                    # 这里可以添加条件来过滤出特定的标签
                    # 例如，按大小、位置或其他特征

                    if rect["bottom"] - rect["top"] > rect["x1"] - rect["x0"] and rect["bottom"] - rect["top"] > 10 and \
                            rect["x1"] - rect["x0"] > 10:
                        bbox = (rect["x0"], rect["top"], rect["x1"], rect["bottom"])
                        bboxes.append((page.page_number, bbox))

            elif texts and texts[0]['text'] != 'ETIQUETA' and texts[0]['text'] != 'Envío:':
                print("第二种")
                # 初始化边界值
                min_x = float('inf')
                min_y = float('inf')
                max_x = float('-inf')
                max_y = float('-inf')

                # 创建存储y坐标值的数组
                y_values = []

                # 检查所有矩形的边界
                for rect in rects:
                    min_x = min(min_x, rect['x0'])
                    max_x = max(max_x, rect['x1'])

                    # 收集top和bottom值
                    current_top = rect['top']
                    current_bottom = rect['bottom']

                    # 检查top值是否可以添加
                    can_add_top = True
                    for existing_y in y_values:
                        if abs(current_top - existing_y) <= 5:
                            can_add_top = False
                            break
                    if can_add_top:
                        y_values.append(current_top)

                    # 检查bottom值是否可以添加
                    can_add_bottom = True
                    for existing_y in y_values:
                        if abs(current_bottom - existing_y) <= 5:
                            can_add_bottom = False
                            break
                    if can_add_bottom:
                        y_values.append(current_bottom)

                # 检查所有文本的边界
                for text in texts:
                    min_x = min(min_x, text['x0'])
                    max_x = max(max_x, text['x1'])

                    # 收集top和bottom值
                    current_top = text['top']
                    current_bottom = text['bottom']

                    # 检查top值是否可以添加
                    can_add_top = True
                    for existing_y in y_values:
                        if abs(current_top - existing_y) <= 5:
                            can_add_top = False
                            break
                    if can_add_top:
                        y_values.append(current_top)

                    # 检查bottom值是否可以添加
                    can_add_bottom = True
                    for existing_y in y_values:
                        if abs(current_bottom - existing_y) <= 5:
                            can_add_bottom = False
                            break
                    if can_add_bottom:
                        y_values.append(current_bottom)

                # 添加padding（确保不超出页面边界）
                min_x = max(0, min_x - 0)
                max_x = min(page.width, max_x + 0)

                # 对y_values进行排序
                y_values.sort()

                # 判断y_values数组长度是否为偶数，如果是则按配对处理
                if len(y_values) > 0 and len(y_values) % 2 == 0:
                    for i in range(0, len(y_values), 2):
                        top_value = y_values[i]
                        bottom_value = y_values[i + 1]
                        bbox = (min_x, top_value, max_x, bottom_value)
                        bboxes.append((page.page_number, bbox))
            elif texts and texts[0]['text'] == 'ETIQUETA':
                # 如果没有找到普通矩形，尝试提取浅色边框
                print("第三种")
                # 使用自定义设置提取边框
                edges = page.edges
                x0 = 0
                x1 = 0
                top = 0
                bottom = 0
                # 创建存储bottom值的数组
                bottom_values = []
                print(rects)
                if rects:
                    # 根据边缘信息重建矩形
                    # 按照x0坐标分组找到垂直边
                    for edge in rects:
                        print(str(edge["x1"] - edge["x0"]) + " - " + str(edge["bottom"] - edge["top"]))
                        # if edge["orientation"] is not None:

                        # x0 = edge["x0"]
                        # x1 = edge["x1"]
                        # top = edge["top"]
                        # bottom = edge["bottom"]
                        # bbox = (x0, top, x1, bottom)
                        # bboxes.append((page.page_number, bbox))
                        # 避免除零错误
                        height = edge["bottom"] - edge["top"]
                        width = edge["x1"] - edge["x0"]
                        if height > 0 and width > 0:  # 确保高度不为零
                            proportion = width / height
                            print(proportion)
                            if (proportion > 1.4 and proportion < 1.6) or (proportion > 0.95 and proportion < 1.05):
                                x0 = edge["x0"]
                                x1 = edge["x1"]
                                top = edge["top"]
                                bottom = edge["bottom"]
                                bbox = (x0, top, x1, bottom)
                                bboxes.append((page.page_number, bbox))

    return bboxes  # 返回所有标签的边界框列表


def crop_and_save(pdf_path, output_file="output.pdf", total_boxes=0):
    doc = fitz.open(pdf_path)  # 打开PDF文档
    bboxes = detect_label_bboxes(pdf_path)  # 检测标签边界框

    # 检查bboxes是否为空
    if not bboxes:
        doc.close()  # 关闭文档
        raise ValueError("该文件可处理内容为空，未检测到任何可裁剪的标签")
    # print(bboxes)
    if len(bboxes) != (total_boxes * 2) and len(bboxes) != total_boxes:
        print("该文件可处理内容与总箱数不符:" + str(len(bboxes)) + "-" + str(total_boxes))
        raise ValueError("该文件可处理内容与总箱数不符:" + str(len(bboxes)) + "-" + str(total_boxes))

    # 创建一个新的PDF文档用于保存所有裁剪后的页面
    output_doc = fitz.open()

    if len(bboxes) == (total_boxes * 2):
        for idx, (page_num, bbox) in enumerate(bboxes, 1):
            if idx % 2 == 1:
                # 获取当前页面
                page = doc[page_num - 1]
                # 创建一个矩形对象，表示裁剪区域
                rect = fitz.Rect(bbox[0], bbox[1], bbox[2], bbox[3])

                # 在新文档中创建一个新页面，大小与裁剪区域相同
                new_page = output_doc.new_page(width=rect.width, height=rect.height)

                # 将原始页面的裁剪区域绘制到新页面上
                new_page.show_pdf_page(
                    fitz.Rect(0, 0, rect.width, rect.height),  # 新页面的矩形区域
                    doc,  # 原始文档
                    page_num - 1,  # 原始页面编号
                    clip=rect,  # 裁剪区域
                )
    elif len(bboxes) == total_boxes:
        for idx, (page_num, bbox) in enumerate(bboxes, 1):
            # 获取当前页面
            page = doc[page_num - 1]
            # 创建一个矩形对象，表示裁剪区域
            rect = fitz.Rect(bbox[0], bbox[1], bbox[2], bbox[3])

            # 在新文档中创建一个新页面，大小与裁剪区域相同
            new_page = output_doc.new_page(width=rect.width, height=rect.height)

            # 将原始页面的裁剪区域绘制到新页面上
            new_page.show_pdf_page(
                fitz.Rect(0, 0, rect.width, rect.height),  # 新页面的矩形区域
                doc,  # 原始文档
                page_num - 1,  # 原始页面编号
                clip=rect,  # 裁剪区域
            )

    # 保存所有裁剪后的页面为一个新的PDF文件
    output_doc.save(output_file)
    output_doc.close()  # 关闭新文档
    doc.close()  # 关闭原文档


def add_summary_page(pdf_path, shipping_id, shipments, total_boxes, warehouse, date=None):
    """
    为PDF添加一个总结页面，字体加粗，Total、Fecha 和 Almacén 三行显示在PDF最下方
    货件信息每行显示两个

    参数:
    - pdf_path: PDF文件路径
    - shipping_id: 送仓单号
    - shipments: 货件信息数组，每个元素包含 tracking_number 和 begin end
    - total_boxes: 总箱数
    - warehouse: 仓库信息
    - date: 日期
    """
    # 打开PDF
    doc = fitz.open(pdf_path)

    # 创建新页面 (宽度15.2cm, 高度10.4cm, 转换为点)
    width = 15.2 * 28.35  # 厘米转点
    height = 10.4 * 28.35  # 厘米转点
    page = doc.new_page(-1, width=width, height=height)

    # 设置字体和格式 - 加大加粗
    title_font_size = 20  # 标题字体大小
    content_font_size = 12  # 内容字体大小
    text_color = (0, 0, 0)  # 黑色

    # 计算文本位置
    margin_top = 30
    margin_left = 20
    line_height = 24
    right_margin = width - 50  # 右边距，用于右对齐
    mid_point = width / 2  # 页面中点，用于分隔左右两个货件信息

    # 计算页面底部位置，留出三行文本的空间
    bottom_margin = height - 20
    bottom_line_3 = bottom_margin - line_height * 2  # Almacén
    bottom_line_2 = bottom_margin - line_height * 1  # Fecha
    bottom_line_1 = bottom_margin  # Total

    # 添加送仓单号 (加粗)
    page.insert_text(
        (margin_left, margin_top),
        f"Envío: {shipping_id}",
        fontsize=title_font_size,
        color=text_color,
        fontname="Helvetica-Bold"  # 使用粗体字
    )

    # 添加货件信息 (每行两个)
    current_y = margin_top + line_height

    # 处理货件信息，每行显示两个
    for i in range(0, len(shipments), 2):
        # 检查当前行是否会与底部三行重叠
        if current_y + line_height >= bottom_line_3 - line_height:
            # 如果会重叠，则不再显示更多货件信息
            break

        # 处理左侧货件
        if i < len(shipments):
            shipment = shipments[i]
            tracking_number = shipment.get('tracking_number', '')
            begin = shipment.get('begin', '')
            end = shipment.get('end', '')

            # 格式化箱号范围
            box_text = f"#{begin}-{end}"

            # 添加左侧货件信息 (加粗)
            page.insert_text(
                (margin_left, current_y),
                f"{tracking_number} {box_text}",
                fontsize=title_font_size,
                color=text_color,
                fontname="Helvetica-Bold"
            )

        # 处理右侧货件
        if i + 1 < len(shipments):
            shipment = shipments[i + 1]
            tracking_number = shipment.get('tracking_number', '')
            begin = shipment.get('begin', '')
            end = shipment.get('end', '')

            # 格式化箱号范围
            box_text = f"#{begin}-{end}"

            # 添加右侧货件信息 (加粗)
            page.insert_text(
                (mid_point + 20, current_y),
                f"{tracking_number} {box_text}",
                fontsize=title_font_size,
                color=text_color,
                fontname="Helvetica-Bold"
            )

        # 每处理完一行（两个货件），垂直位置下移
        current_y += line_height
    # 如果shipments超过12个，则在下方增加一行提示：“...（超出12个记录不展示，请在指令详情页面查看）”
    if len(shipments) > 12:
        page.insert_text(
            (margin_left, bottom_line_3 - line_height),
            "..." + "(No se muestran más de 12 registros)",
            fontsize=title_font_size,
            color=text_color,
            fontname="Helvetica-Bold"
        )

    # 添加总箱数 (右对齐, 加粗)，放在最下方的一行
    total_text = f"Total: {total_boxes} {'cajas' if int(total_boxes) > 1 else 'caja'}"
    tw = fitz.get_text_length(total_text, fontname="Helvetica-Bold", fontsize=title_font_size)
    page.insert_text(
        (right_margin - tw, bottom_line_3),
        total_text,
        fontsize=title_font_size,
        color=text_color,
        fontname="Helvetica-Bold"
    )

    # 添加日期 (右对齐, 加粗)，放在倒数第二行
    current_date = date

    fecha_text = f"Fecha: {current_date}"
    tw = fitz.get_text_length(fecha_text, fontname="Helvetica-Bold", fontsize=title_font_size)
    page.insert_text(
        (right_margin - tw, bottom_line_2),
        fecha_text,
        fontsize=title_font_size,
        color=text_color,
        fontname="Helvetica-Bold"
    )

    # 添加仓库信息 (右对齐, 加粗)，放在倒数第三行
    almacen_text = f"Almacén: {warehouse}"
    tw = fitz.get_text_length(almacen_text, fontname="Helvetica-Bold", fontsize=title_font_size)
    page.insert_text(
        (right_margin - tw, bottom_line_1),
        almacen_text,
        fontsize=title_font_size,
        color=text_color,
        fontname="Helvetica-Bold"
    )

    # 创建一个临时文件路径
    temp_path = pdf_path + ".temp"

    # 保存PDF到临时文件
    doc.save(temp_path)
    doc.close()

    # 关闭文档后，用临时文件替换原始文件
    if os.path.exists(temp_path):
        os.replace(temp_path, pdf_path)


def crop_and_save_with_summary(pdf_path, output_file, shipping_id, shipments, total_boxes, warehouse, date=None):
    """
    裁剪PDF并添加总结页

    参数:
    - pdf_path: 输入PDF路径
    - output_file: 输出PDF路径
    - shipping_id: 送仓单号
    - shipments: 货件信息数组，每个元素包含 tracking_number 和 begin end
    - total_boxes: 总箱数
    - warehouse: 仓库信息
    - date: 日期，如果为None则使用当前日期
    """
    try:
        # 先执行原有的裁剪功能
        crop_and_save(pdf_path, output_file, total_boxes)

        # 然后添加总结页
        add_summary_page(output_file, shipping_id, shipments, total_boxes, warehouse, date)

        return output_file
    except ValueError as e:
        # 重新抛出ValueError异常，保持原始错误信息
        raise ValueError(str(e))
    except Exception as e:
        # 处理其他可能的异常
        raise Exception(f"处理PDF时发生错误: {str(e)}")


if __name__ == "__main__":
    # 测试代码 (实际使用时可以删除或注释掉)
    try:
        # 测试带总结页的功能
        result = crop_and_save_with_summary(
            os.path.join("uploads/外箱标.pdf"),
            os.path.join("download/外箱标.pdf"),
            "36123456",
            [{"tracking_number": "566001233435", "begin": 1, "end": 530}],
            94,
            "MXRC02",
            "15/02"
        )
        print(f"处理成功，输出文件: {result}")
    except ValueError as e:
        print(f"错误: {str(e)}")
    except Exception as e:
        print(f"发生错误: {str(e)}")
